home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MIDICraft's MIDINET CD-ROM
/
MIDICraft's MIDINET CD-ROM.iso
/
DOSUTILS
/
MAPNOTES.ZIP
/
MAPNOTES.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-03-11
|
8KB
|
368 lines
// mapnotes v1.0 written by Günter Nagler 1996 (gnagler@ihm.tu-graz.ac.at)
#include "midiio.hpp"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#ifdef __MSDOS__
#define WRITE_BINARY "wb"
#define READ_BINARY "rb"
#else
#define WRITE_BINARY "w"
#define READ_BINARY "r"
#endif
char* input = 0;
char* output = 0;
char* changename = "mapnotes.chg";
int quiet = 0;
int changechannel[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int changenote[128];
class MidiChangeNotes : public MidiCopy
{
public:
MidiChangeNotes(char* name);
virtual void noteon(int channel, int note, int vel);
virtual void noteoff(int channel, int note, int vel);
virtual void error(const char* msg);
virtual void percent(int perc);
};
MidiChangeNotes::MidiChangeNotes(char* name) : MidiCopy(name)
{
options_ = OPTION_NOSYSEVENTS | OPTION_NOMETAEVENTS | OPTION_NOCONTROLS;
}
void MidiChangeNotes::noteon(int channel, int note, int vel)
{
if (changechannel[channel])
{
note = changenote[note];
}
MidiCopy::noteon(channel, note, vel);
}
void MidiChangeNotes::noteoff(int channel, int note, int vel)
{
if (changechannel[channel])
{
note = changenote[note];
}
MidiCopy::noteoff(channel, note, vel);
}
void MidiChangeNotes::percent(int perc)
{
if (!quiet)
fprintf(stderr, "%-3d%%\r", perc);
}
void MidiChangeNotes::error(const char* msg)
{
printf("// error: %s\n", msg);
}
void usage()
{
fprintf(stderr, "mapnotes changes notes in midi files\n");
fprintf(stderr, "usage: mapnotes [-chg file.chg] [-c #[-#]] [-quiet] file.mid changed.mid\n");
fprintf(stderr, "-chg file.chg\tload note changes from file.chg (default is mapnotes.chg)\n");
fprintf(stderr, "-c #\t\tmodify programs on channel (1-16, default: all channels except GM drum channel 10)\n");
fprintf(stderr, "-quiet\t\tbe quiet! does not write percentage info\n");
exit(1);
}
char* loadline(FILE* f, char* s)
{
int c;
char* t = s;
while ((c = fgetc(f)) != EOF && c != '\n')
{
if (c == '\r')
continue;
*t++ = c;
}
*t = 0;
if (c == EOF && s == t)
return 0;
return s;
}
char* skipws(char* &s)
{
while (*s != 0 && isspace(*s))
s++;
return s;
}
char* getword(char* &s)
{
static char word[256];
char* w = word;
skipws(s);
w = word;
while (*s != 0 && !isspace(*s))
*w++ = *s++;
*w = '\0';
return word;
}
static char* GMNote[128] =
{
"C0","C#0","D0","D#0","E0","F0","F#0","G0","G#0","A0","A#0","B0",
"C1","C#1","D1","D#1","E1","F1","F#1","G1","G#1","A1","A#1","B1",
"C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2","A2","A#2","B2",
"C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3","A3","A#3","B3",
"C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4","A4","A#4","B4",
"C5","C#5","D5","D#5","E5","F5","F#5","G5","G#5","A5","A#5","B5",
"C6","C#6","D6","D#6","E6","F6","F#6","G6","G#6","A6","A#6","B6",
"C7","C#7","D7","D#7","E7","F7","F#7","G7","G#7","A7","A#7","B7",
"C8","C#8","D8","D#8","E8","F8","F#8","G8","G#8","A8","A#8","B8",
"C9","C#9","D9","D#9","E9","F9","F#9","G9","G#9","A9","A#9","B9",
"C10","C#10","D10","D#10","E10","F10","F#10","G10"
};
int equali(char* s1, char* s2)
{
if (!s1 || !s2)
return 0;
while (*s1 != 0 && *s2 != 0)
if (toupper(*s1++) != toupper(*s2++))
return 0;
if (*s1 != *s2)
return 0;
return 1;
}
int getnumber(char* word)
{
char* s = word;
int v = 0;
if (*s == '-')
return -1;
if (isdigit(*s))
{
while (*s && isdigit(*s))
v = v * 10 + (*s++ - '0');
}
else if (*s == '$' || strncmp(s, "0x",2) == 0 ||strncmp(s, "0X", 2) == 0)
{
if (*s == '$')
s++;
else
s+=2;
while (*s && isxdigit(*s))
{
if (isdigit(*s))
v = (v << 4) + (*s - '0');
else
v = (v << 4) + (toupper(*s) - 'A' + 10);
s++;
}
}
else
{
fprintf(stderr, "Number expected instead of %s\n", word);
return -1;
}
if (*s != '\0')
fprintf(stderr, "Invalid characters in number %s\n", word);
return v;
}
int getnote(char* s)
{
if (strcmp(s, "-") == 0)
return -1;
for (int i = 0; i < 128; i++)
if (equali(s, GMNote[i]))
return i;
return getnumber(s);
}
int loadchangetable(char* filename)
{
FILE* f = fopen(filename, READ_BINARY);
static char line[256];
char *lp;
int oldnote, newnote;
for (int i = 0; i < 128;i++)
changenote[i] = i;
if (!f)
{
perror(filename);
return 0;
}
while (loadline(f, line))
{
char* word;
lp = line;
word = strchr(lp, ';'); // remove comment!
if (word)
*word = '\0';
// get note name
word = getword(lp);
if (*word == 0) // empty line!
continue;
oldnote = getnote(word);
if (oldnote < 0)
continue;
skipws(lp);
if (strncmp(lp, "=>", 2) == 0)
lp += 2;
word = getword(lp);
// get note value (can be empty (-))
if (!*word)
{
fprintf(stderr, "invalid line format: %s\n", line);
continue;
}
newnote = getnote(word);
changenote[oldnote] = newnote;
}
fclose(f);
return 1;
}
int main(int argc, char**argv)
{
argc--; argv++;
while (argc > 0 && **argv == '-')
{
if (strncmp(*argv, "-chg", 3) == 0)
{
argc--; argv++;
if (argc == 0)
{
fprintf(stderr, "option -chg needs filename parameter\n");
continue;
}
changename = *argv++; argc--;
continue;
}
if (strncmp(*argv, "-c", 2) == 0)
{
int firstchannel, secondchannel;
argc--; argv++;
if (argc > 0 && sscanf(*argv, "%u-%u", &firstchannel, &secondchannel) == 2)
{
if (firstchannel <= 0 || secondchannel > 16)
{
fprintf(stderr, "channel number %s out of range 1-16\n", *argv);
firstchannel = secondchannel = -1;
}
else if (firstchannel > secondchannel)
{
fprintf(stderr, "%s: first channel number must be less than second one\n", *argv);
firstchannel = secondchannel = -1;
}
argc--; argv++;
}
else if (argc > 0 && isdigit(**argv))
{
firstchannel = atoi(*argv);
if (firstchannel <= 0 || firstchannel > 16)
{
fprintf(stderr, "channel number %s out of range 1-16\n", *argv);
firstchannel = -1;
}
secondchannel = firstchannel;
argc--; argv++;
}
else
{
fprintf(stderr, "option -mapchannel expects two channel numbers 1-16\n");
usage();
break;
}
for (int i = firstchannel; i <= secondchannel; i++)
changechannel[i] = 1;
continue;
}
if (strncmp(*argv, "-quiet", 2) == 0)
{
quiet = 1;
argc--; argv++; continue;
}
fprintf(stderr, "invalid option %s\n", *argv);
argc--; argv++;
usage();
}
for (int i = 0; i < 16; i++)
if (changechannel[i])
break;
if (i >= 16) // no channel set => modify all channels
{
for (i = 0; i < 16; i++)
changechannel[i] = 1;
changechannel[9] = 0; // gm drum
}
if (!loadchangetable(changename))
return 0;
if (argc < 2)
usage();
input = argv[0];
output = argv[1];
if (strcmp(input, output) == 0)
{
fprintf(stderr, "cannot convert midi to same file\n");
return 1;
}
MidiChangeNotes midi(input);
if (!midi.getf())
{
perror(input);
return 1;
}
MidiWrite* write = new MidiWrite(output);
if (!write)
{
fprintf(stderr, "out of memory\n");
return 1;
}
if (!write->getf())
{
perror(output);
return 1;
}
midi.setoutput(write);
midi.options_ = OPTION_NOSYSEVENTS;
argc--; argv++;
if (!midi.run())
fprintf(stderr, "%s: midi read error at %04lX\n", input, midi.getpos());
delete write;
return 0;
}